package cz.pecinovsky.česky.oopnz.správce;
/*******************************************************************************
 *<pre>
 * Předchozí: {@code Obdélník} v balíčku {@code tvary}
 * Následující: Prozatím není
 *
 * Přidáno:
 *    - U metod deklarovaných v rozhraní {@code ITvar}
 *      jsou uvedeny anotace {@code @Override}
 *    - Metoda {@link nakresli(Kreslítko)}
 *    - Atribut třídy {@link SP} odkazující na správce plátna
 * Upraveno:
 *    - Převedena pod {@link SprávcePlátna}
 *      - Upravena metoda {@code nakresli}
 *      - Implicitní velikost kroku je odvozena od kroku správce plátna
 *      - Meotdy {@link nakresli()} a {@link smaž()} nyní
 *        přihlašují a odhlašují instanci u správce plátna
 *
 * Projekt  125c - Přepravka
 *   ~ Změna deklarovaných metod v důsledku zavedení přepravek
 *     - Konstruktory přebírající parametry v přepravkách
 *     - Přístupové metody využívající a vracející přepravky
 *
 * Projekt  133z - Balíčky
 *   + Přidány importy tříd a rozhraní přestěhovaných do jiných balíčků
 *
 * Projekt  Ppp
 *   ~ Změna atributu {@code název} na nekonstantní
 *   + Metoda {@code setNázev(String)}
 *
 * Projekt  Ppp
 *   + Přidáno
 *   - Odebráno
 *   ~ Změněno
 *</pre>
 */

////////////////////////////////////////////////////////////////////////////////
//%%+  +++++ Konec ignorovaného počátečního textu +++++

//%A+ >=133x
import cz.pecinovsky.česky.oopnz.utility.Barva;
import cz.pecinovsky.česky.oopnz.utility.Oblast;
import cz.pecinovsky.česky.oopnz.utility.Pozice;
import cz.pecinovsky.česky.oopnz.utility.Rozměr;

//%A-


/*******************************************************************************
 * Instance třídy {@code Obdélník} představují obdélníky určené
 * pro práci na virtuálním plátně při prvním seznámení s třídami a objekty.
 *
 * @author Rudolf PECINOVSKÝ
 * @version 6.03.2017 — 2010-11-08
 */
public class Obdélník implements ITvar
{
//== KONSTANTNÍ ATRIBUTY TŘÍDY =================================================

    /** Počáteční barva nakreslené instance v případě,
     *  kdy uživatel žádnou požadovanou barvu nezadá -
     *  pro obdélník Barva.ČERVENÁ. */
    public static final Barva IMPLICITNÍ_BARVA = Barva.ČERVENÁ;

    /** Plátno, na které se bude instance kreslit. */
    private static final SprávcePlátna SP = SprávcePlátna.getInstance();



//== PROMĚNNÉ ATRIBUTY TŘÍDY ===================================================

    /** Počet vytvořených instancí */
    private static int počet = 0;



//== STATICKÝ INICIALIZAČNÍ BLOK - STATICKÝ KONSTRUKTOR ========================
//== KONSTANTNÍ ATRIBUTY INSTANCÍ ==============================================

    /** Pořadí vytvoření dané instance v rámci třídy. */
    private final int pořadí = ++počet;

//%I+ <125
//    /** Název sestávající z názvu třídy a pořadí instance */
//    private final String název = "Obdélník_" + pořadí;
//
//%I-


//== PROMĚNNÉ ATRIBUTY INSTANCÍ ================================================
//%A+ >125

    /** Název instance sestávající implicitně
     *  z jednoduchého názvu třídy následovaného potržítkem a
     *  pořadím vytvoření instance v rámci instancí této třídy. */
    private String název = "Obdélník_" + pořadí;
//%A-

    /** Bodová x-ová souřadnice instance. */
    private int xPos;

    /** Bodová y-ová souřadnice instance. */
    private int yPos;

    /** Šířka v bodech. */
    protected int šířka;

    /** Výška v bodech. */
    protected int výška;

    /** Barva instance. */
    private Barva barva;



//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ TŘÍDY ========================================
//== OSTATNÍ NESOUKROMÉ METODY TŘÍDY ===========================================

//##############################################################################
//== KONSTRUKTORY A TOVÁRNÍ METODY =============================================

    /***************************************************************************
     * Připraví novou instanci s implicitním umístěním, rozměry a barvou.
     * Instance bude umístěna v levém horním rohu plátna
     * a bude mít implicitní barvu,
     * výšku rovnu kroku a šířku dvojnásobku kroku plátna.
     */
    public Obdélník()
    {
        this( 0, 0, 2*SP.getKrok(), SP.getKrok() );
    }


    /***************************************************************************
     * Připraví novou instanci se zadanou pozicí a rozměry
     * a implicitní barvou.
     *
     * @param x       Vodorovná (x-ová) souřadnice instance,
     *                x=0 má levý okraj plátna, souřadnice roste doprava
     * @param y       Svislá (y-ová) souřadnice instance,
     *                y=0 má horní okraj plátna, souřadnice roste dolů
     * @param šířka   Šířka vytvářené instance,  šířka > 0
     * @param výška   Výška vytvářené instance,  výška > 0
     */
    public Obdélník( int x, int y, int šířka, int výška )
    {
        this( x, y, šířka, výška, IMPLICITNÍ_BARVA );
    }

//%A+ >125

    /***************************************************************************
     * Připraví novou instanci se zadanou pozicí, rozměry a barvou.
     *
     * @param pozice    Pozice vytvářené instance
     * @param rozměr    Rozměr vytvářené instance
     * @param barva     Barva vytvářené instance
     */
    public Obdélník(Pozice pozice, Rozměr rozměr, Barva barva)
    {
        this( pozice.x, pozice.y, rozměr.šířka, rozměr.výška, barva );
    }


    /***************************************************************************
     * Vytvoří novou instanci vyplňující zadanou oblast
     * a mající zadanou barvu.
     *
     * @param oblast   Oblast definující pozici a rozměr vytvářené instance
     * @param barva    Barva vytvářené instance
     */
    public Obdélník(Oblast oblast, Barva barva)
    {
        this( oblast.x, oblast.y, oblast.šířka, oblast.výška, barva );
    }

//%A-

    /***************************************************************************
     * Připraví novou instanci se zadanou pozicí, rozměry a barvou.
     *
     * @param x       Vodorovná (x-ová) souřadnice instance,
     *                x=0 má levý okraj plátna, souřadnice roste doprava
     * @param y       Svislá (y-ová) souřadnice instance,
     *                y=0 má horní okraj plátna, souřadnice roste dolů
     * @param šířka   Šířka vytvářené instance,  šířka > 0
     * @param výška   Výška vytvářené instance,  výška > 0
     * @param barva   Barva vytvářené instance
     */
    public Obdélník( int x, int y, int šířka, int výška, Barva barva )
    {
        //Test platnosti parametru
        if ((šířka<=0) || (výška<=0)) {
            throw new IllegalArgumentException(
                "\nnew Obdélník - Parametry nemají povolené hodnoty: x="
                + x + ", y=" + y + ", šířka=" + šířka + ", výška=" + výška );
        }

        //Parametry akceptovány --> můžeme tvořit
        this.xPos  = x;
        this.yPos  = y;
        this.šířka = šířka;
        this.výška = výška;
        this.barva = barva;
    }


    /***************************************************************************
     * Vrátí kopii daného tvaru,
     * tj. stejný tvar, stejně velký, stejně umístěný a se stejnou barvou.
     *
     * @return Požadovaná kopie
     */
    @Override
    public Obdélník kopie()
    {
        return new Obdélník(xPos, yPos, šířka, výška, barva);
    }



//== ABSTRAKTNÍ METODY =========================================================
//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ INSTANCÍ =====================================

    /***************************************************************************
     * Vrátí x-ovou (vodorovnou) souřadnici pozice instance.
     *
     * @return  Aktuální vodorovná (x-ová) souřadnice instance,
     *          x=0 má levý okraj plátna, souřadnice roste doprava
     */
//%I+ <125
//    @Override
//%I-
    public int getX()
    {
        return xPos;
    }


    /***************************************************************************
     * Vrátí y-ovou (svislou) souřadnici pozice instance.
     *
     * @return  Aktuální svislá (y-ová) souřadnice instance,
     *          y=0 má horní okraj plátna, souřadnice roste dolů
     */
//%I+ <125
//    @Override
//%I-
    public int getY()
    {
        return yPos;
    }

//%A+ >125

    /***************************************************************************
     * Vrátí instanci třídy {@code Pozice} s aktuální pozicí instance.
     *
     * @return  Instance třídy {@code Pozice} s aktuální pozicí instance
     */
    @Override
    public Pozice getPozice()
    {
        return new Pozice( getX(), getY() );
    }


    /***************************************************************************
     * Nastaví novou pozici instance.
     *
     * @param pozice   Nastavovaná pozice instance
     */
    @Override
    public void setPozice(Pozice pozice)
    {
        setPozice( pozice.x, pozice.y );
    }

//%A-

    /***************************************************************************
     * Nastaví novou pozici instance.
     *
     * @param x  Nově nastavovaná vodorovná (x-ová) souřadnice instance,
     *           x=0 má levý okraj plátna, souřadnice roste doprava
     * @param y  Nově nastavovaná svislá (y-ová) souřadnice instance,
     *           y=0 má horní okraj plátna, souřadnice roste dolů
     */
    @Override
    public void setPozice(int x, int y)
    {
        xPos = x;
        yPos = y;
        SP.překresli();
    }


    /***************************************************************************
     * Vrátí šířku instance v bodech.
     *
     * @return  Aktuální šířka instance v bodech
     */
//%I+ <125
//    @Override
//%I-
     public int getŠířka()
     {
         return šířka;
     }


    /***************************************************************************
     * Vrátí výšku instance v bodech.
     *
     * @return  Aktuální výška instance v bodech
     */
//%I+ <125
//    @Override
//%I-
     public int getVýška()
     {
         return výška;
     }

//%A+ >125

    /***************************************************************************
     * Vrátí instanci třídy {@code Rozměr} s aktuálními rozměry instance.
     *
     * @return   Instance třídy {@code Rozměr} s aktuálními rozměry instance
     */
    @Override
    public Rozměr getRozměr()
    {
        return new Rozměr( getŠířka(), getVýška() );
    }


    /***************************************************************************
     * Nastaví nové rozměry instance.
     *
     * @param rozměr    Nově nastavovaný rozměr
     */
    @Override
    public void setRozměr(Rozměr rozměr)
    {
        setRozměr( rozměr.šířka, rozměr.výška );
    }

//%A-

    /***************************************************************************
     * Nastaví nový "čtvercový" rozměr instance -
     * na zadaný rozměr se nastaví výška i šířka.
     *
     * @param rozměr  Nově nastavovaný rozměr v obou směrech; rozměr>0
     */
    public void setRozměr(int rozměr)
    {
        setRozměr( rozměr, rozměr );
    }


    /***************************************************************************
     * Nastaví nové rozměry instance. Nastavované rozměry musí být nezáporné,
     * místo nulového rozměru se nastaví rozměr rovný jedné.
     *
     * @param šířka    Nově nastavovaná šířka; šířka >= 0
     * @param výška    Nově nastavovaná výška; výška >= 0
     */
    @Override
    public void setRozměr(int šířka, int výška)
    {
        if( (šířka < 0) || (výška < 0) ) {
            throw new IllegalArgumentException(
            "Rozměry musí byt nezáporné: šířka=" + šířka + ", výška=" + výška);
        }
        this.šířka = Math.max(1, šířka);
        this.výška = Math.max(1, výška);
        SP.překresli();
    }

//%A+ >125

    /***************************************************************************
     * Vrátí instanci třídy {@code Oblast} s informacemi
     * o aktuální pozici a rozměrech instance.
     *
     * @return   Instance třídy {@code Oblast} s informacemi
     *           o aktuální pozici a rozměrech instance
     */
    public Oblast getOblast()
    {
        return new Oblast( getX(), getY(), getŠířka(), getVýška() );
    }


    /***************************************************************************
     * Nastaví novou polohu a rozměry instance prostřednictvím
     * instance třídy {@code Oblast}.
     *
     * @param oblast Nově nastavovaná oblast zaujímaná instancí
     */
    public void setOblast(Oblast oblast)
    {
        setOblast( oblast.x, oblast.y, oblast.šířka, oblast.výška );
    }


    /***************************************************************************
     * Nastaví pozici a rozměr objektu.
     *
     * @param pozice  Nově nastavovaná pozice objektu
     * @param rozměr  Nově nastavovaný rozměr objektu
     */
    public void setOblast( Pozice pozice, Rozměr rozměr )
    {
        setOblast( pozice.x, pozice.y, rozměr.šířka, rozměr.výška );
    }


    /***************************************************************************
     * Nastaví novou pozici a rozměr objektu.
     *
     * @param x       Vodorovná (x-ová) souřadnice instance,
     *                x=0 má levý okraj plátna, souřadnice roste doprava
     * @param y       Svislá (y-ová) souřadnice instance,
     *                y=0 má horní okraj plátna, souřadnice roste dolů
     * @param šířka   Šířka vytvářeného objektu v bodech
     * @param výška   Výška vytvářeného objektu v bodech
     */
    public void setOblast( int x, int y, int šířka, int výška )
    {
        SP.nekresli(); {
            setPozice( x,     y     );
            setRozměr( šířka, výška );
        } SP.vraťKresli();
    }

//%A-

    /***************************************************************************
     * Vrátí aktuální barvu instance.
     *
     * @return Instance třídy {@code Barva} definující aktuálně nastavenou barvu
     */
    public Barva getBarva()
    {
        return barva;
    }


    /***************************************************************************
     * Nastaví novou barvu instance.
     *
     * @param nová  Požadovaná nová barva
     */
    public void setBarva(Barva nová)
    {
        barva = nová;
        SP.překresli();
    }


    /***************************************************************************
//%X+ >125
     * Vrátí název instance, tj. název její třídy následovaný
//%X-
//%A+ >125
     * Vrátí název instance, implicitně název její třídy následovaný
//%A-
     * pořadím vytvoření instance v rámci instancí této třídy.
     *
     * @return  Řetězec s názvem instance
     */
    public String getNázev()
    {
        return název;
    }

//%A+ >125

    /***************************************************************************
     * Nastaví nový název instance.
     *
     * @param název  Řetězec s novým názvem instance
     */
    public void setNázev(String název)
    {
        this.název = název;
    }

//%A-


//== OSTATNÍ NESOUKROMÉ METODY INSTANCÍ ========================================

    /***************************************************************************
     * Vrátí podpis instance, tj. její řetězcovou reprezentaci.
     * Používá se především při ladění.
     *
     * @return Řetězcová reprezentace (podpis) dané instance
     */
    @Override
    public String toString()
    {
        return název + "_(x=" + xPos + ",y=" + yPos  +
               ",šířka=" + šířka + ",výška=" + výška +
               ",barva=" + barva + ")";
    }


    /***************************************************************************
     * Prostřednictvím dodaného kreslítka vykreslí obraz své instance.
     *
     * @param kreslítko Kreslítko, které nakreslí instanci
     */
    @Override
    public void nakresli( Kreslítko kreslítko )
    {
        kreslítko.vyplňRám( xPos, yPos, šířka, výška, barva );
    }


    /***************************************************************************
     * Přihlásí se u správce plátna.
     */
    public void nakresli()
    {
        SP.přidej(this);
    }


    /***************************************************************************
     * Odhlásí se u správce plátna.
     */
    public void smaž()
    {
        SP.odstraň(this);
    }


    /***************************************************************************
     * Přesune instanci o zadaný počet bodů vpravo,
     * při záporné hodnotě parametru vlevo.
     *
     * @param vzdálenost Vzdálenost, o kterou se instance přesune
     */
    public void posunVpravo(int vzdálenost)
    {
        setPozice( xPos+vzdálenost, yPos );
    }


    /***************************************************************************
     * Přesune instanci o implicitní počet bodů vpravo.
     * Tento počet definuje správce plátna a je možno jej zjistit
     * zavoláním jeho metody {@link getKrok()}
     * a nastavit zavoláním jeho metody {@link setKrok(int)},
     * resp. {@link setKrokRozměr(int,int,int)}.
     */
    public void posunVpravo()
    {
        posunVpravo( SP.getKrok() );
    }


    /***************************************************************************
     * Přesune instanci o implicitní počet bodů vlevo.
     * Tento počet definuje správce plátna a je možno jej zjistit
     * zavoláním jeho metody {@link getKrok()}
     * a nastavit zavoláním jeho metody {@link setKrok(int)},
     * resp. {@link setKrokRozměr(int,int,int)}.
     */
    public void posunVlevo()
    {
        posunVpravo( -SP.getKrok() );
    }


    /***************************************************************************
     * Přesune instanci o zadaný počet bodů dolů,
     * při záporné hodnotě parametru nahoru.
     *
     * @param vzdálenost   Počet bodů, o které se instance přesune
     */
    public void posunDolů(int vzdálenost)
    {
        setPozice( xPos, yPos+vzdálenost );
    }


    /***************************************************************************
     * Přesune instanci o implicitní počet bodů dolů.
     * Tento počet definuje správce plátna a je možno jej zjistit
     * zavoláním jeho metody {@link getKrok()}
     * a nastavit zavoláním jeho metody {@link setKrok(int)},
     * resp. {@link setKrokRozměr(int,int,int)}.
     */
    public void posunDolů()
    {
        posunDolů( SP.getKrok() );
    }


    /***************************************************************************
     * Přesune instanci o implicitní počet bodů nahoru.
     * Tento počet definuje správce plátna a je možno jej zjistit
     * zavoláním jeho metody {@link getKrok()}
     * a nastavit zavoláním jeho metody {@link setKrok(int)},
     * resp. {@link setKrokRozměr(int,int,int)}.
     */
    public void posunVzhůru()
    {
        posunDolů( -SP.getKrok() );
    }



//== SOUKROMÉ A POMOCNÉ METODY TŘÍDY ===========================================
//== SOUKROMÉ A POMOCNÉ METODY INSTANCÍ ========================================
//== INTERNÍ DATOVÉ TYPY =======================================================
//== TESTOVACÍ METODY A TŘÍDY ==================================================
}
